#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <stdarg.h>
#include <assert.h>
#include <ctype.h>
#include "ILexer.h"
#include "Scintilla.h"
#include "SciLexer.h"
#include "WordList.h"
#include "LexAccessor.h"
#include "Accessor.h"
#include "StyleContext.h"
#include "CharacterSet.h"
#include "LexerModule.h"

#ifdef SCI_NAMESPACE
using namespace Scintilla;
#endif

static bool strstart( const char *haystack, const char *needle ) {
  return strncmp( haystack, needle, strlen( needle ) ) == 0;
}

static bool Is0To9( char ch ) {
  return ( ch >= '0' ) && ( ch <= '9' );
}

static bool Is1To9( char ch ) {
  return ( ch >= '1' ) && ( ch <= '9' );
}

static bool IsAlphabetic( int ch ) {
  return IsASCII( ch ) && isalpha( ch );
}

static inline bool AtEOL( Accessor &styler, unsigned int i ) {
  return ( styler[i] == '\n' ) ||
         ( ( styler[i] == '\r' ) && ( styler.SafeGetCharAt( i + 1 ) != '\n' ) );
}

#define DIFF_BUFFER_START_SIZE 16



static void ColouriseDiffLine( char *lineBuffer, int endLine, Accessor &styler ) {
  if( 0 == strncmp( lineBuffer, "diff ", 5 ) ) {
    styler.ColourTo( endLine, SCE_DIFF_COMMAND );
  } else if( 0 == strncmp( lineBuffer, "Index: ", 7 ) ) {
    styler.ColourTo( endLine, SCE_DIFF_COMMAND );
  } else if( 0 == strncmp( lineBuffer, "---", 3 ) && lineBuffer[3] != '-' ) {
    if( lineBuffer[3] == ' ' && atoi( lineBuffer + 4 ) && !strchr( lineBuffer, '/' ) ) {
      styler.ColourTo( endLine, SCE_DIFF_POSITION );
    } else if( lineBuffer[3] == '\r' || lineBuffer[3] == '\n' ) {
      styler.ColourTo( endLine, SCE_DIFF_POSITION );
    } else
    { styler.ColourTo( endLine, SCE_DIFF_HEADER ); }
  } else if( 0 == strncmp( lineBuffer, "+++ ", 4 ) ) {
    if( atoi( lineBuffer + 4 ) && !strchr( lineBuffer, '/' ) ) {
      styler.ColourTo( endLine, SCE_DIFF_POSITION );
    } else
    { styler.ColourTo( endLine, SCE_DIFF_HEADER ); }
  } else if( 0 == strncmp( lineBuffer, "====", 4 ) ) {
    styler.ColourTo( endLine, SCE_DIFF_HEADER );
  } else if( 0 == strncmp( lineBuffer, "***", 3 ) ) {
    if( lineBuffer[3] == ' ' && atoi( lineBuffer + 4 ) && !strchr( lineBuffer, '/' ) ) {
      styler.ColourTo( endLine, SCE_DIFF_POSITION );
    } else if( lineBuffer[3] == '*' ) {
      styler.ColourTo( endLine, SCE_DIFF_POSITION );
    } else
    { styler.ColourTo( endLine, SCE_DIFF_HEADER ); }
  } else if( 0 == strncmp( lineBuffer, "? ", 2 ) ) {
    styler.ColourTo( endLine, SCE_DIFF_HEADER );
  } else if( lineBuffer[0] == '@' ) {
    styler.ColourTo( endLine, SCE_DIFF_POSITION );
  } else if( lineBuffer[0] >= '0' && lineBuffer[0] <= '9' ) {
    styler.ColourTo( endLine, SCE_DIFF_POSITION );
  } else if( lineBuffer[0] == '-' || lineBuffer[0] == '<' ) {
    styler.ColourTo( endLine, SCE_DIFF_DELETED );
  } else if( lineBuffer[0] == '+' || lineBuffer[0] == '>' ) {
    styler.ColourTo( endLine, SCE_DIFF_ADDED );
  } else if( lineBuffer[0] == '!' ) {
    styler.ColourTo( endLine, SCE_DIFF_CHANGED );
  } else if( lineBuffer[0] != ' ' ) {
    styler.ColourTo( endLine, SCE_DIFF_COMMENT );
  } else {
    styler.ColourTo( endLine, SCE_DIFF_DEFAULT );
  }
}

static void ColouriseDiffDoc( unsigned int startPos, int length, int, WordList *[], Accessor &styler ) {
  char lineBuffer[DIFF_BUFFER_START_SIZE] = "";
  styler.StartAt( startPos );
  styler.StartSegment( startPos );
  unsigned int linePos = 0;
  for( unsigned int i = startPos; i < startPos + length; i++ ) {
    if( AtEOL( styler, i ) ) {
      if( linePos < DIFF_BUFFER_START_SIZE ) {
        lineBuffer[linePos] = 0;
      }
      ColouriseDiffLine( lineBuffer, i, styler );
      linePos = 0;
    } else if( linePos < DIFF_BUFFER_START_SIZE - 1 ) {
      lineBuffer[linePos++] = styler[i];
    } else if( linePos == DIFF_BUFFER_START_SIZE - 1 ) {
      lineBuffer[linePos++] = 0;
    }
  }
  if( linePos > 0 ) {
    if( linePos < DIFF_BUFFER_START_SIZE ) {
      lineBuffer[linePos] = 0;
    }
    ColouriseDiffLine( lineBuffer, startPos + length - 1, styler );
  }
}

static void FoldDiffDoc( unsigned int startPos, int length, int, WordList *[], Accessor &styler ) {
  int curLine = styler.GetLine( startPos );
  int curLineStart = styler.LineStart( curLine );
  int prevLevel = curLine > 0 ? styler.LevelAt( curLine - 1 ) : SC_FOLDLEVELBASE;
  int nextLevel;
  do {
    int lineType = styler.StyleAt( curLineStart );
    if( lineType == SCE_DIFF_COMMAND ) {
      nextLevel = SC_FOLDLEVELBASE | SC_FOLDLEVELHEADERFLAG;
    } else if( lineType == SCE_DIFF_HEADER ) {
      nextLevel = ( SC_FOLDLEVELBASE + 1 ) | SC_FOLDLEVELHEADERFLAG;
    } else if( lineType == SCE_DIFF_POSITION && styler[curLineStart] != '-' ) {
      nextLevel = ( SC_FOLDLEVELBASE + 2 ) | SC_FOLDLEVELHEADERFLAG;
    } else if( prevLevel & SC_FOLDLEVELHEADERFLAG ) {
      nextLevel = ( prevLevel & SC_FOLDLEVELNUMBERMASK ) + 1;
    } else
    { nextLevel = prevLevel; }
    if( ( nextLevel & SC_FOLDLEVELHEADERFLAG ) && ( nextLevel == prevLevel ) ) {
      styler.SetLevel( curLine - 1, prevLevel & ~SC_FOLDLEVELHEADERFLAG );
    }
    styler.SetLevel( curLine, nextLevel );
    prevLevel = nextLevel;
    curLineStart = styler.LineStart( ++curLine );
  } while( static_cast<int>( startPos ) + length > curLineStart );
}

static inline bool isassignchar( unsigned char ch ) {
  return ( ch == '=' ) || ( ch == ':' );
}

static void ColourisePropsLine(
  char *lineBuffer,
  unsigned int lengthLine,
  unsigned int startLine,
  unsigned int endPos,
  Accessor &styler,
  bool allowInitialSpaces ) {
  unsigned int i = 0;
  if( allowInitialSpaces ) {
    while( ( i < lengthLine ) && isspacechar( lineBuffer[i] ) ) {
      i++;
    }
  } else {
    if( isspacechar( lineBuffer[i] ) ) {
      i = lengthLine;
    }
  }
  if( i < lengthLine ) {
    if( lineBuffer[i] == '#' || lineBuffer[i] == '!' || lineBuffer[i] == ';' ) {
      styler.ColourTo( endPos, SCE_PROPS_COMMENT );
    } else if( lineBuffer[i] == '[' ) {
      styler.ColourTo( endPos, SCE_PROPS_SECTION );
    } else if( lineBuffer[i] == '@' ) {
      styler.ColourTo( startLine + i, SCE_PROPS_DEFVAL );
      if( isassignchar( lineBuffer[i++] ) ) {
        styler.ColourTo( startLine + i, SCE_PROPS_ASSIGNMENT );
      }
      styler.ColourTo( endPos, SCE_PROPS_DEFAULT );
    } else {
      while( ( i < lengthLine ) && !isassignchar( lineBuffer[i] ) ) {
        i++;
      }
      if( ( i < lengthLine ) && isassignchar( lineBuffer[i] ) ) {
        styler.ColourTo( startLine + i - 1, SCE_PROPS_KEY );
        styler.ColourTo( startLine + i, SCE_PROPS_ASSIGNMENT );
        styler.ColourTo( endPos, SCE_PROPS_DEFAULT );
      } else
      { styler.ColourTo( endPos, SCE_PROPS_DEFAULT ); }
    }
  } else {
    styler.ColourTo( endPos, SCE_PROPS_DEFAULT );
  }
}

static void ColourisePropsDoc( unsigned int startPos, int length, int, WordList *[], Accessor &styler ) {
  char lineBuffer[1024];
  styler.StartAt( startPos );
  styler.StartSegment( startPos );
  unsigned int linePos = 0;
  unsigned int startLine = startPos;
  bool allowInitialSpaces = styler.GetPropertyInt( "lexer.props.allow.initial.spaces", 1 ) != 0;
  for( unsigned int i = startPos; i < startPos + length; i++ ) {
    lineBuffer[linePos++] = styler[i];
    if( AtEOL( styler, i ) || ( linePos >= sizeof( lineBuffer ) - 1 ) ) {
      lineBuffer[linePos] = '\0';
      ColourisePropsLine( lineBuffer, linePos, startLine, i, styler, allowInitialSpaces );
      linePos = 0;
      startLine = i + 1;
    }
  }
  if( linePos > 0 ) {
    ColourisePropsLine( lineBuffer, linePos, startLine, startPos + length - 1, styler, allowInitialSpaces );
  }
}



static void FoldPropsDoc( unsigned int startPos, int length, int, WordList *[], Accessor &styler ) {
  bool foldCompact = styler.GetPropertyInt( "fold.compact", 1 ) != 0;
  unsigned int endPos = startPos + length;
  int visibleChars = 0;
  int lineCurrent = styler.GetLine( startPos );
  char chNext = styler[startPos];
  int styleNext = styler.StyleAt( startPos );
  bool headerPoint = false;
  int lev;
  for( unsigned int i = startPos; i < endPos; i++ ) {
    char ch = chNext;
    chNext = styler[i + 1];
    int style = styleNext;
    styleNext = styler.StyleAt( i + 1 );
    bool atEOL = ( ch == '\r' && chNext != '\n' ) || ( ch == '\n' );
    if( style == SCE_PROPS_SECTION ) {
      headerPoint = true;
    }
    if( atEOL ) {
      lev = SC_FOLDLEVELBASE;
      if( lineCurrent > 0 ) {
        int levelPrevious = styler.LevelAt( lineCurrent - 1 );
        if( levelPrevious & SC_FOLDLEVELHEADERFLAG ) {
          lev = SC_FOLDLEVELBASE + 1;
        } else
        { lev = levelPrevious & SC_FOLDLEVELNUMBERMASK; }
      }
      if( headerPoint ) {
        lev = SC_FOLDLEVELBASE;
      }
      if( visibleChars == 0 && foldCompact ) {
        lev |= SC_FOLDLEVELWHITEFLAG;
      }
      if( headerPoint ) {
        lev |= SC_FOLDLEVELHEADERFLAG;
      }
      if( lev != styler.LevelAt( lineCurrent ) ) {
        styler.SetLevel( lineCurrent, lev );
      }
      lineCurrent++;
      visibleChars = 0;
      headerPoint = false;
    }
    if( !isspacechar( ch ) ) {
      visibleChars++;
    }
  }
  if( lineCurrent > 0 ) {
    int levelPrevious = styler.LevelAt( lineCurrent - 1 );
    if( levelPrevious & SC_FOLDLEVELHEADERFLAG ) {
      lev = SC_FOLDLEVELBASE + 1;
    } else
    { lev = levelPrevious & SC_FOLDLEVELNUMBERMASK; }
  } else {
    lev = SC_FOLDLEVELBASE;
  }
  int flagsNext = styler.LevelAt( lineCurrent );
  styler.SetLevel( lineCurrent, lev | ( flagsNext & ~SC_FOLDLEVELNUMBERMASK ) );
}

static void ColouriseMakeLine(
  char *lineBuffer,
  unsigned int lengthLine,
  unsigned int startLine,
  unsigned int endPos,
  Accessor &styler ) {
  unsigned int i = 0;
  int lastNonSpace = -1;
  unsigned int state = SCE_MAKE_DEFAULT;
  bool bSpecial = false;
  bool bCommand = false;
  if( ( lengthLine > 0 ) && ( lineBuffer[0] == '\t' ) ) {
    bCommand = true;
  }
  while( ( i < lengthLine ) && isspacechar( lineBuffer[i] ) ) {
    i++;
  }
  if( i < lengthLine ) {
    if( lineBuffer[i] == '#' ) {
      styler.ColourTo( endPos, SCE_MAKE_COMMENT );
      return;
    }
    if( lineBuffer[i] == '!' ) {
      styler.ColourTo( endPos, SCE_MAKE_PREPROCESSOR );
      return;
    }
  }
  int varCount = 0;
  while( i < lengthLine ) {
    if( ( ( i + 1 ) < lengthLine ) && ( lineBuffer[i] == '$' && lineBuffer[i + 1] == '(' ) ) {
      styler.ColourTo( startLine + i - 1, state );
      state = SCE_MAKE_IDENTIFIER;
      varCount++;
    } else if( state == SCE_MAKE_IDENTIFIER && lineBuffer[i] == ')' ) {
      if( --varCount == 0 ) {
        styler.ColourTo( startLine + i, state );
        state = SCE_MAKE_DEFAULT;
      }
    }
    if( !bSpecial && !bCommand ) {
      if( lineBuffer[i] == ':' ) {
        if( ( ( i + 1 ) < lengthLine ) && ( lineBuffer[i + 1] == '=' ) ) {
          if( lastNonSpace >= 0 ) {
            styler.ColourTo( startLine + lastNonSpace, SCE_MAKE_IDENTIFIER );
          }
          styler.ColourTo( startLine + i - 1, SCE_MAKE_DEFAULT );
          styler.ColourTo( startLine + i + 1, SCE_MAKE_OPERATOR );
        } else {
          if( lastNonSpace >= 0 ) {
            styler.ColourTo( startLine + lastNonSpace, SCE_MAKE_TARGET );
          }
          styler.ColourTo( startLine + i - 1, SCE_MAKE_DEFAULT );
          styler.ColourTo( startLine + i, SCE_MAKE_OPERATOR );
        }
        bSpecial = true;
        state = SCE_MAKE_DEFAULT;
      } else if( lineBuffer[i] == '=' ) {
        if( lastNonSpace >= 0 ) {
          styler.ColourTo( startLine + lastNonSpace, SCE_MAKE_IDENTIFIER );
        }
        styler.ColourTo( startLine + i - 1, SCE_MAKE_DEFAULT );
        styler.ColourTo( startLine + i, SCE_MAKE_OPERATOR );
        bSpecial = true;
        state = SCE_MAKE_DEFAULT;
      }
    }
    if( !isspacechar( lineBuffer[i] ) ) {
      lastNonSpace = i;
    }
    i++;
  }
  if( state == SCE_MAKE_IDENTIFIER ) {
    styler.ColourTo( endPos, SCE_MAKE_IDEOL );
  } else {
    styler.ColourTo( endPos, SCE_MAKE_DEFAULT );
  }
}

static void ColouriseMakeDoc( unsigned int startPos, int length, int, WordList *[], Accessor &styler ) {
  char lineBuffer[1024];
  styler.StartAt( startPos );
  styler.StartSegment( startPos );
  unsigned int linePos = 0;
  unsigned int startLine = startPos;
  for( unsigned int i = startPos; i < startPos + length; i++ ) {
    lineBuffer[linePos++] = styler[i];
    if( AtEOL( styler, i ) || ( linePos >= sizeof( lineBuffer ) - 1 ) ) {
      lineBuffer[linePos] = '\0';
      ColouriseMakeLine( lineBuffer, linePos, startLine, i, styler );
      linePos = 0;
      startLine = i + 1;
    }
  }
  if( linePos > 0 ) {
    ColouriseMakeLine( lineBuffer, linePos, startLine, startPos + length - 1, styler );
  }
}

static int RecogniseErrorListLine( const char *lineBuffer, unsigned int lengthLine, int &startValue ) {
  if( lineBuffer[0] == '>' ) {
    return SCE_ERR_CMD;
  } else if( lineBuffer[0] == '<' ) {
    return SCE_ERR_DIFF_DELETION;
  } else if( lineBuffer[0] == '!' ) {
    return SCE_ERR_DIFF_CHANGED;
  } else if( lineBuffer[0] == '+' ) {
    if( strstart( lineBuffer, "+++ " ) ) {
      return SCE_ERR_DIFF_MESSAGE;
    } else
    { return SCE_ERR_DIFF_ADDITION; }
  } else if( lineBuffer[0] == '-' ) {
    if( strstart( lineBuffer, "--- " ) ) {
      return SCE_ERR_DIFF_MESSAGE;
    } else
    { return SCE_ERR_DIFF_DELETION; }
  } else if( strstart( lineBuffer, "cf90-" ) ) {
    return SCE_ERR_ABSF;
  } else if( strstart( lineBuffer, "fortcom:" ) ) {
    return SCE_ERR_IFORT;
  } else if( strstr( lineBuffer, "File \"" ) && strstr( lineBuffer, ", line " ) ) {
    return SCE_ERR_PYTHON;
  } else if( strstr( lineBuffer, " in " ) && strstr( lineBuffer, " on line " ) ) {
    return SCE_ERR_PHP;
  } else if( ( strstart( lineBuffer, "Error " ) ||
               strstart( lineBuffer, "Warning " ) ) &&
             strstr( lineBuffer, " at (" ) &&
             strstr( lineBuffer, ") : " ) &&
             ( strstr( lineBuffer, " at (" ) < strstr( lineBuffer, ") : " ) ) ) {
    return SCE_ERR_IFC;
  } else if( strstart( lineBuffer, "Error " ) ) {
    return SCE_ERR_BORLAND;
  } else if( strstart( lineBuffer, "Warning " ) ) {
    return SCE_ERR_BORLAND;
  } else if( strstr( lineBuffer, "at line " ) &&
             ( strstr( lineBuffer, "at line " ) < ( lineBuffer + lengthLine ) ) &&
             strstr( lineBuffer, "file " ) &&
             ( strstr( lineBuffer, "file " ) < ( lineBuffer + lengthLine ) ) ) {
    return SCE_ERR_LUA;
  } else if( strstr( lineBuffer, " at " ) &&
             ( strstr( lineBuffer, " at " ) < ( lineBuffer + lengthLine ) ) &&
             strstr( lineBuffer, " line " ) &&
             ( strstr( lineBuffer, " line " ) < ( lineBuffer + lengthLine ) ) &&
             ( strstr( lineBuffer, " at " ) + 4 < ( strstr( lineBuffer, " line " ) ) ) ) {
    return SCE_ERR_PERL;
  } else if( ( memcmp( lineBuffer, "   at ", 6 ) == 0 ) &&
             strstr( lineBuffer, ":line " ) ) {
    return SCE_ERR_NET;
  } else if( strstart( lineBuffer, "Line " ) &&
             strstr( lineBuffer, ", file " ) ) {
    return SCE_ERR_ELF;
  } else if( strstart( lineBuffer, "line " ) &&
             strstr( lineBuffer, " column " ) ) {
    return SCE_ERR_TIDY;
  } else if( strstart( lineBuffer, "\tat " ) &&
             strstr( lineBuffer, "(" ) &&
             strstr( lineBuffer, ".java:" ) ) {
    return SCE_ERR_JAVA_STACK;
  } else if( strstart( lineBuffer, "In file included from " ) ||
             strstart( lineBuffer, "                 from " ) ) {
    return SCE_ERR_GCC_INCLUDED_FROM;
  } else {
    bool initialTab = ( lineBuffer[0] == '\t' );
    bool initialColonPart = false;
    bool canBeCtags = !initialTab;
    enum { stInitial,
           stGccStart, stGccDigit, stGccColumn, stGcc,
           stMsStart, stMsDigit, stMsBracket, stMsVc, stMsDigitComma, stMsDotNet,
           stCtagsStart, stCtagsFile, stCtagsStartString, stCtagsStringDollar, stCtags,
           stUnrecognized
         } state = stInitial;
    for( unsigned int i = 0; i < lengthLine; i++ ) {
      char ch = lineBuffer[i];
      char chNext = ' ';
      if( ( i + 1 ) < lengthLine ) {
        chNext = lineBuffer[i + 1];
      }
      if( state == stInitial ) {
        if( ch == ':' ) {
          if( ( chNext != '\\' ) && ( chNext != '/' ) && ( chNext != ' ' ) ) {
            state = stGccStart;
          } else if( chNext == ' ' ) {
            initialColonPart = true;
          }
        } else if( ( ch == '(' ) && Is1To9( chNext ) && ( !initialTab ) ) {
          state = stMsStart;
        } else if( ( ch == '\t' ) && canBeCtags ) {
          state = stCtagsStart;
        } else if( ch == ' ' ) {
          canBeCtags = false;
        }
      } else if( state == stGccStart ) {
        state = Is1To9( ch ) ? stGccDigit : stUnrecognized;
      } else if( state == stGccDigit ) {
        if( ch == ':' ) {
          state = stGccColumn;
          startValue = i + 1;
        } else if( !Is0To9( ch ) ) {
          state = stUnrecognized;
        }
      } else if( state == stGccColumn ) {
        if( !Is0To9( ch ) ) {
          state = stGcc;
          if( ch == ':' ) {
            startValue = i + 1;
          }
          break;
        }
      } else if( state == stMsStart ) {
        state = Is0To9( ch ) ? stMsDigit : stUnrecognized;
      } else if( state == stMsDigit ) {
        if( ch == ',' ) {
          state = stMsDigitComma;
        } else if( ch == ')' ) {
          state = stMsBracket;
        } else if( ( ch != ' ' ) && !Is0To9( ch ) ) {
          state = stUnrecognized;
        }
      } else if( state == stMsBracket ) {
        if( ( ch == ' ' ) && ( chNext == ':' ) ) {
          state = stMsVc;
        } else if( ( ch == ':' && chNext == ' ' ) || ( ch == ' ' ) ) {
          char word[512];
          unsigned int j, chPos;
          unsigned numstep;
          chPos = 0;
          if( ch == ' ' ) {
            numstep = 1;
          } else
          { numstep = 2; }
          for( j = i + numstep; j < lengthLine && IsAlphabetic( lineBuffer[j] ) && chPos < sizeof( word ) - 1; j++ ) {
            word[chPos++] = lineBuffer[j];
          }
          word[chPos] = 0;
          if( !CompareCaseInsensitive( word, "error" ) || !CompareCaseInsensitive( word, "warning" ) ||
              !CompareCaseInsensitive( word, "fatal" ) || !CompareCaseInsensitive( word, "catastrophic" ) ||
              !CompareCaseInsensitive( word, "note" ) || !CompareCaseInsensitive( word, "remark" ) ) {
            state = stMsVc;
          } else
          { state = stUnrecognized; }
        } else
        { state = stUnrecognized; }
      } else if( state == stMsDigitComma ) {
        if( ch == ')' ) {
          state = stMsDotNet;
          break;
        } else if( ( ch != ' ' ) && !Is0To9( ch ) ) {
          state = stUnrecognized;
        }
      } else if( state == stCtagsStart ) {
        if( ch == '\t' ) {
          state = stCtagsFile;
        }
      } else if( state == stCtagsFile ) {
        if( ( lineBuffer[i - 1] == '\t' ) &&
            ( ( ch == '/' && chNext == '^' ) || Is0To9( ch ) ) ) {
          state = stCtags;
          break;
        } else if( ( ch == '/' ) && ( chNext == '^' ) ) {
          state = stCtagsStartString;
        }
      } else if( ( state == stCtagsStartString ) && ( ( lineBuffer[i] == '$' ) && ( lineBuffer[i + 1] == '/' ) ) ) {
        state = stCtagsStringDollar;
        break;
      }
    }
    if( state == stGcc ) {
      return initialColonPart ? SCE_ERR_LUA : SCE_ERR_GCC;
    } else if( ( state == stMsVc ) || ( state == stMsDotNet ) ) {
      return SCE_ERR_MS;
    } else if( ( state == stCtagsStringDollar ) || ( state == stCtags ) ) {
      return SCE_ERR_CTAG;
    } else
    { return SCE_ERR_DEFAULT; }
  }
}

static void ColouriseErrorListLine(
  char *lineBuffer,
  unsigned int lengthLine,
  unsigned int endPos,
  Accessor &styler,
  bool valueSeparate ) {
  int startValue = -1;
  int style = RecogniseErrorListLine( lineBuffer, lengthLine, startValue );
  if( valueSeparate && ( startValue >= 0 ) ) {
    styler.ColourTo( endPos - ( lengthLine - startValue ), style );
    styler.ColourTo( endPos, SCE_ERR_VALUE );
  } else {
    styler.ColourTo( endPos, style );
  }
}

static void ColouriseErrorListDoc( unsigned int startPos, int length, int, WordList *[], Accessor &styler ) {
  char lineBuffer[10000];
  styler.StartAt( startPos );
  styler.StartSegment( startPos );
  unsigned int linePos = 0;
  bool valueSeparate = styler.GetPropertyInt( "lexer.errorlist.value.separate", 0 ) != 0;
  for( unsigned int i = startPos; i < startPos + length; i++ ) {
    lineBuffer[linePos++] = styler[i];
    if( AtEOL( styler, i ) || ( linePos >= sizeof( lineBuffer ) - 1 ) ) {
      lineBuffer[linePos] = '\0';
      ColouriseErrorListLine( lineBuffer, linePos, i, styler, valueSeparate );
      linePos = 0;
    }
  }
  if( linePos > 0 ) {
    ColouriseErrorListLine( lineBuffer, linePos, startPos + length - 1, styler, valueSeparate );
  }
}

static const char *const emptyWordListDesc[] = {
  0
};

static void ColouriseNullDoc( unsigned int startPos, int length, int, WordList *[],
                              Accessor &styler ) {
  if( length > 0 ) {
    styler.StartAt( startPos + length - 1 );
    styler.StartSegment( startPos + length - 1 );
    styler.ColourTo( startPos + length - 1, 0 );
  }
}

LexerModule lmDiff( SCLEX_DIFF, ColouriseDiffDoc, "diff", FoldDiffDoc, emptyWordListDesc );
LexerModule lmProps( SCLEX_PROPERTIES, ColourisePropsDoc, "props", FoldPropsDoc, emptyWordListDesc );
LexerModule lmMake( SCLEX_MAKEFILE, ColouriseMakeDoc, "makefile", 0, emptyWordListDesc );
LexerModule lmErrorList( SCLEX_ERRORLIST, ColouriseErrorListDoc, "errorlist", 0, emptyWordListDesc );
LexerModule lmNull( SCLEX_NULL, ColouriseNullDoc, "null" );
